/* 使用插件的方式执行命令 */
const fs = require('fs')
const ExecuteResolver = require('./ExecuteResolver')

class Executor {
  constructor ({ executor, command, stdout, stderr, cwd, user, group }, resolver = ExecuteResolver) {
    this._command = command
    this._stdout = stdout
    this._stderr = stderr
    this._cwd = cwd
    this._user = user
    this._group = group
    this._execute = this._loadExecutor(executor)
    this._resolver = resolver
  }

  execute () {
    try {
      this._execute({
        command: this._command,
        stdout: this._stdout,
        stderr: this._stderr,
        cwd: this._cwd,
        uid: this._resolver.uid(this._user),
        gid: this._resolver.gid(this._group)
      })
    } catch (err) {
      if (err instanceof this._resolver.ExecuteResolveError) {
        throw new Executor.ResolveError(err.message)
      } else {
        throw new Executor.ExecuteError(err)
      }
    }
  }

  _loadExecutor (executorName) {
    if (fs.existsSync(`plugins/executors/${executorName}.js`)) {
      const path = `../plugins/executors/${executorName}`
      try {
        return require(path)
      } catch (err) {
        throw new Executor.LoadingError(executorName, err)
      }
    } else {
      throw new Executor.NotFound(executorName)
    }
  }
}

Executor.NotFound = class NotFound extends Error {
  constructor (executor) {
    super(`名为${executor}的excutor插件未找到`)
    this.executor = executor
  }
}

Executor.LoadingError = class LoadingError extends Error {
  constructor (executor, reason) {
    super(`加载名为${executor}的executor插件出现未知错误`)
    this.executor = executor
    this.reason = reason
  }
}

Executor.ResolveError = class ResolveError extends Error {}

Executor.ExecuteError = class ExecuteError extends Error {
  constructor (err) {
    super('执行时出现未知错误')
    this.reason = err
  }
}

module.exports = Executor
